import React from "react";
import ReactDOM from "react-dom";
import { Button, Row, Col, Tooltip } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import { get, set, throttle, cloneDeep } from "lodash";
import { transformData2GUI, extractDefault } from "../../utils"
import "./index.less";

const containerClass = "visbar-gui-array-right-menu";
interface IRightMenuProps {
  top: number;
  left: number;
  options: [{ label: string; key: any }];
  onClick?: (value: any) => void;
}
/** 右侧菜单面板 */
class RightMenu extends React.Component<IRightMenuProps> {
  wrapper: HTMLDivElement;
  constructor(props) {
    super(props);
    this.initWrapper();
    this.wrapper.style.top = `${props.top}px`;
    this.wrapper.style.left = `${props.left}px`;
  }
  initWrapper = () => {
    this.wrapper = document.querySelector(`.${containerClass}`);
    if (!this.wrapper) {
        this.wrapper = document.createElement("div");
        this.wrapper.className = containerClass;
        document.body.appendChild(this.wrapper);
    }
    this.wrapper.innerHTML = "";  /* 新打开一个新的右键菜单时清除别打菜单: 排他性 */
  }
  shouldComponentUpdate(nextProps) {
    if (nextProps.top !== this.props.top || nextProps.left !== this.props.left) {
      if (this.wrapper) {
        this.wrapper.style.top = `${nextProps.top}px`;
        this.wrapper.style.left = `${nextProps.left}px`;
      }
    }
    return true;
  }
  render() {
    const { options, onClick } = this.props;
    return ReactDOM.createPortal(<div className="right-menu-wrapper">
      <ul className="right-menu-list">
        {options.map(op => <li className="right-menu-item" key={op.key} onClick={() => onClick && onClick(op.key)}>{op.label}</li>) }
        </ul>
      </div>, this.wrapper);
  }
}

interface IVArrayProps{
  length: number;
  default?: Array<any>; // 数组默认值
  value?: Array<any>;   // 当前的数据
  defaultActive?: number; // 默认选中的数组项
  defaultNewValue?: any;  // 默认新增的元素值
  childrenList?: any;        // 数组对象的渲染元素数组
  onChange?: (value: any) => void;
  getComponent?: (key: string) => any;
  [key: string]: any;
}
interface IVArrayState {
  activeKey: number;    // 当前激活的数组项
  rightMenuOptions: any;
  value: Array<any>;
}
export default class VArray extends React.Component<IVArrayProps, IVArrayState> {
  constructor(props: IVArrayProps) {
    super(props);
    this.state = {
      activeKey: props.defaultActive || 0,
      rightMenuOptions: null,
      value: this.initValue(),
    }
  }
  initValue = () => {
    const { value, length, defaultNewValue, childrenList } = this.props;
    const result = value || cloneDeep(this.props.default) || [];
    if (result.length < length) {
      for (let idx = result.length; idx < length; idx++){
        result[idx] = extractDefault({ config: childrenList[idx], value: defaultNewValue });
      }
    }
    return result;
  }
  removeRightMenuOptions = () => this.setState({ rightMenuOptions: null })
  componentDidMount() {
    window.addEventListener("click", this.removeRightMenuOptions);
  }
  componentWillUnmount() {
    window.removeEventListener("click", this.removeRightMenuOptions);
  }

  deleteArrayItem = ({ idx }) => {
    const { value, activeKey } = this.state;
    const { onChange } = this.props;
    value.splice(idx, 1);
    this.setState({
      rightMenuOptions: null, value: [...value],
      activeKey: activeKey - 1 >= 0 ? activeKey - 1 : 0
    }, () => {
      onChange && onChange(this.state.value)
    });
  }

  changeHandler = (val, node) => {
    const { onChange, defaultNewValue } = this.props;
    const { activeKey, value } = this.state;
    !value?.[activeKey] && (value[activeKey] = cloneDeep(defaultNewValue) || {});
    set(value[activeKey], node.path?.join("."), val);
    this.setState({ value: [...value] }, () => {
      onChange && onChange(this.state.value);
    });
  }
  throttleChangeHandler = throttle(this.changeHandler, 100);

  showRightMenu = (ev: React.MouseEvent<any>, idx: number) => {
    ev.preventDefault();
    const menuOptions = {
      top: ev.clientY,
      left: ev.clientX,
      options: [{
        label: "删除当前项",
        key: {
          idx,
          type: "delete"
        }
      }],
      onClick: this.deleteArrayItem
    };
    this.setState({ rightMenuOptions: menuOptions })
  }

  addArrayItem = () => {
    const { value } = this.state;
    const { onChange, defaultNewValue } = this.props;
    value.push(cloneDeep(defaultNewValue) || {});
    this.setState({ activeKey: value.length - 1 }, () => {
      onChange && onChange(this.state.value)
    })
  }

  renderChildPane = () => {
    const { activeKey, value } = this.state;
    return <div className="v-array-header">
      {
        value.map((_, idx) => {
          return (<Button onContextMenu={(ev) => this.showRightMenu(ev, idx)} size="small" type={idx === activeKey ? "primary" : "default"}
            key={idx} className="v-array-pane-item"
            onClick={() => this.setState({ activeKey: idx })}
          >
            组{idx + 1}
          </Button>)
        })
      }
      <Button type="default" size="small" className="add-array-item"
        onClick={() => this.addArrayItem()}
      ><PlusOutlined /></Button>
    </div>
  }

  renderComponent = (data = []) => {
    const { getComponent, defaultNewValue } = this.props;
    const { activeKey } = this.state;
    const value = this.state.value[activeKey] || defaultNewValue;
    return data.map(node => {
      const Node = getComponent(node.node);
      if (!Node) return null;
      if (node.children) return <Node {...node} key={node.key} className="visbar-gui-item">{ this.renderComponent(node.children) }</Node>
      if (node.node === "suite") return <Node {...node} Node={getComponent(node.trulyNode)} onChange={(value) => this.throttleChangeHandler(value, node)} />
      return (<Row className="visbar-gui-item visbar-gui-leaf-item" key={node.key}>
          <Col span={6} className="visbar-gui-item-label">
            {
              <Tooltip title={node.description || node.name}>
                <label>{node.name}</label>
              </Tooltip>
            }
          </Col>
          <Col span={18}>
            <Node {...node} value={get(value, node.path)} onChange={(value) => this.throttleChangeHandler(value, node)} />
          </Col>
        </Row>)
    })
  }

  shouldComponentUpdate(nextProps: IVArrayProps, nextState) {
    if (nextProps.value !== this.props.value || nextProps.default !== this.props.default) {
      this.setState({ value: nextProps.value || nextProps.default || this.props.value })
    }
    if (nextProps !== this.props || nextState !== this.state) return true;
    return false;
  }

  render() {
    const { childrenList } = this.props;
    const { rightMenuOptions, activeKey } = this.state;
    return <div className="v-array-wrapper">
      <Row className="v-array-header-wrapper">
        <Col span={6} className="v-array-header-name">
          {this.props.description ? <Tooltip title={this.props.description}><label>{ this.props.name }</label></Tooltip> : <label>{ this.props.name }</label> }
        </Col>
        <Col span={18}>{this.renderChildPane()}</Col>
      </Row>
      {rightMenuOptions && <RightMenu {...rightMenuOptions} />}
      <div className="v-array-main-panel">
        { this.renderComponent(transformData2GUI(childrenList[activeKey] || {})) }
      </div>
    </div>
  }
}